import asyncio
import logging
from os import path
from .comm_handler.comm import CommHandler
from .mqtt_client import MqttClient

_log = logging.getLogger('commSerial')


# 通信服务
# deviceProtocol设备协议:proto_645,modbus_slaves
class CommService:
    def __init__(self, filePath: str, deviceProtocol: dict, mqttClient: MqttClient):
        self.filePath = filePath
        self.mqttClient = mqttClient
        # 串口服务器列表
        self.comList: list[CommHandler] = []
        # 遍历通信协议 modbus,645
        for key, value in deviceProtocol.items():
            if value is not None:
                self.load_comms(key, value)

    # 遍历串口服务器列表
    def load_comms(self, tag, comms: list):
        for config in comms:
            # 串口服务器
            handle = CommHandler(tag, config, self.mqttClient, self.filePath)
            self.comList.append(handle)

    # 开始采集数据
    async def start(self):
        self._stop_event = asyncio.Event()
        self.tasks = [asyncio.create_task(
            self.run_scheduler(h)) for h in self.comList]
        await asyncio.gather(*self.tasks, return_exceptions=True)

    # 辅助函数：循环等待 interval 秒或 stop_event 被 set
    async def wait_interval_or_stop(self, interval: float, step: float = 0.5):
        waited = 0.0
        while waited < interval:
            if self._stop_event.is_set():
                break
            await asyncio.sleep(step)
            waited += step

    # 循环执行方法读取数据
    async def run_scheduler(self, handle: CommHandler):
        interval = handle.commConfig["devicepool"]
        while not self._stop_event.is_set():
            await handle.run_async_client()
            # 等待下一个周期，可被 stop() 打断
            await self.wait_interval_or_stop(interval)

    async def stop(self):
        self._stop_event.set()
        for t in self.tasks:
            t.cancel()
        await asyncio.gather(*self.tasks, return_exceptions=True)
        _log.info("所有程序都已停止")
